# -*- coding: utf-8 -*-
# created on 2017/5/24
#

from __future__ import division
import math
from sklearn.linear_model import LinearRegression
from sympy.abc import b, a
from mathsolver.functions.base import *
from mathsolver.functions.base.base import new_latex

# 求回归方程
"""
1.输入: table = {'x': [8, 10, 11, 12, 14],'y': [21, 25, 26, 28, 35]}
"""


class GLTJHuiGuiFangCheng001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        dx = []
        dy = []
        for i in range(len(table['x'])):
            dx.append([table['x'][i]])
            dy.append([table['y'][i]])
        model = LinearRegression()
        model.fit(dx, dy)
        self.steps.append(["", "设回归方程为%s, 则" % BaseEq([y, b * x + a]).printing()])
        # 系数
        b_value = round(model.coef_[0][0], 3)
        self.steps.append(["", "%s" % BaseEq([b, b_value]).printing()])
        # 截距项
        a_value = round(model.intercept_[0], 3)
        self.steps.append(["", "%s" % BaseEq([a, a_value]).printing()])
        self.steps.append(["", "∴ 回归方程为: %s" % BaseEq([y, b_value * x + a_value]).printing()])
        return self


# 求回归方程的预测值
"""
1.输入: table = {'x': [8, 10, 11, 12, 14],'y': [21, 25, 26, 28, 35]}, target = ['y', 35]
"""


class GLTJHuiGuiFangCheng002(BaseFunction):
    def solver(self, *args):
        table = args[0]
        target = args[1]
        dx = []
        dy = []
        for i in range(len(table['x'])):
            dx.append([table['x'][i]])
            dy.append([table['y'][i]])
        model = LinearRegression()
        model.fit(dx, dy)
        self.steps.append(["", "设回归方程为%s, 则" % BaseEq([y, b * x + a]).printing()])
        # 系数
        b_value = round(model.coef_[0][0], 3)
        self.steps.append(["", "%s" % BaseEq([b, b_value]).printing()])
        # 截距项
        a_value = round(model.intercept_[0], 3)
        self.steps.append(["", "%s" % BaseEq([a, a_value]).printing()])
        self.steps.append(["", "∴ 回归方程为: %s" % BaseEq([y, b_value * x + a_value]).printing()])
        y_value = b_value * x + a_value
        if target[0] == 'x':
            y_value = y_value.subs({x: target[1]})
            self.steps.append(
                ["", "当%s = %s时, %s" % (new_latex(x), new_latex(target[1]), BaseEq([y, y_value]).printing())])
        else:
            expr = y - y_value
            expr = expr.subs({y: target[1]})
            self.steps.append(
                ["", "当%s = %s时, %s" % (new_latex(y), new_latex(target[1]), BaseEq([expr, S.Zero]).printing())])
            self.steps.append(["", "解方程, 得"])
            answer = solve(expr, x)[0]
            self.steps.append(["", "%s" % BaseEq([x, answer]).printing()])
        return self


# 求回归方程的表中参数
"""
1.输入: 
    table = {'x': [3,4,5,6],'y': [2.5,3,4,"a"]}
    b = 0.7
    a = 0.35
"""


class GLTJHuiGuiFangCheng003(BaseFunction):
    def solver(self, *args):
        table = args[0]
        b_value = args[1]
        a_value = args[2]
        len_table = len(table['x'])
        sum_x = 0
        sum_y = 0
        for i in range(len_table):
            sum_x += sympify(table['x'][i])
            sum_y += sympify(table['y'][i])
        self.steps.append(["", "∵ 回归方程为: %s" % BaseEq([y, b_value * x + a_value]).printing()])
        self.steps.append(["", "由回归方程直线必定过平均值点, 可知"])
        average_x = sum_x / len_table
        average_y = sum_y / len_table
        self.steps.append(["", "平均值分别为%s, %s" % (new_latex(average_x), new_latex(average_y))])
        self.steps.append(["", "代入, 得"])
        y_value = b_value * x + a_value
        expr = y - y_value
        expr = expr.subs({x: average_x, y: average_y})
        self.steps.append(["", "%s" % BaseEq([expr, S.Zero]).printing()])
        symbols = list(expr.free_symbols)
        assert len(symbols)
        symbol = symbols[0]
        answer = solve(expr, symbol)[0]
        self.steps.append(["", "解方程, 得"])
        self.steps.append(["", "%s" % BaseEq([symbol, answer]).printing()])
        return self


# 判断最优的回归方程类型
"""
1.输入: table = {'x': [1, 2, 3, 4, 5, 7, 10, 11, 20,25], 'y': [9.02, 5.27,4.06, 3.00,2.59,  2.28,2.21,1.89,1.80,1.75]}
       list_choice=['一次函数方程','反比例函数方程']
"""


class GLTJHuiGuiFangCheng004(BaseFunction):
    def solver(self, *args):
        table = args[0]
        list_choice = args[1]
        list_residues = []
        for choice in list_choice:
            if choice == '一次函数方程':
                dx = []
                dy = []
                for i in range(len(table['x'])):
                    dx.append([table['x'][i]])
                    dy.append([table['y'][i]])

                model = LinearRegression()
                model.fit(dx, dy)
                self.steps.append(["", "设回归方程为%s, 则" % BaseEq([y, b * x + a]).printing()])
                # 系数
                b_value = round(model.coef_[0][0], 3)
                self.steps.append(["", "%s" % BaseEq([b, b_value]).printing()])
                # 截距项
                a_value = round(model.intercept_[0], 3)
                self.steps.append(["", "%s" % BaseEq([a, a_value]).printing()])
                self.steps.append(["", "∴ 一次函数回归方程为: %s" % BaseEq([y, b_value * x + a_value]).printing()])
                self.steps.append(["", "误差为: %s" % new_latex(a_value)])
                list_residues.append(a_value)
            elif choice == '反比例函数方程':
                table_inversely = {'x': [], 'y': []}
                for i in range(len(table['x'])):
                    table_inversely['x'].append((float("%.2f" % (1 / table['x'][i]))))
                    table_inversely['y'].append(table['y'][i])
                dx = []
                dy = []
                for i in range(len(table_inversely['x'])):
                    dx.append([table_inversely['x'][i]])
                    dy.append([table_inversely['y'][i]])
                model = LinearRegression()
                model.fit(dx, dy)
                self.steps.append(["", "设回归方程为%s, 则" % BaseEq([y, b / x + a]).printing()])
                # 系数
                b_value = round(model.coef_[0][0], 3)
                self.steps.append(["", "%s" % BaseEq([b, b_value]).printing()])
                # 截距项
                a_value = round(model.intercept_[0], 3)
                self.steps.append(["", "%s" % BaseEq([a, a_value]).printing()])
                self.steps.append(["", "∴ 反比例函数回归方程为: %s" % BaseEq([y, b_value / x + a_value]).printing()])
                self.steps.append(["", "误差为: %s" % new_latex(a_value)])
                list_residues.append(a_value)
            zuiyouleixing = list_choice[list_residues.index(min(list_residues))]
        self.steps.append(["", "比较误差可知, %s是更优的选择" % zuiyouleixing])
        return self


# 求相关系数
"""
1.输入: table = {'x': [30, 35, 40,45,50], 'y':[5, 8, 10,14,18]}
"""


class GLTJCorrCoef001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        dx = []
        dy = []

        for i in range(len(table['x'])):
            dx.append(table['x'][i])
            dy.append(table['y'][i])
        nn = len(dx)
        # 求和
        sum1 = sum(dx)
        sum2 = sum(dy)
        # 求乘积之和
        sumof_xy = 0.0
        for i in range(len(dx)):
            temp = dx[i] * dy[i]
            sumof_xy += temp
        # 求平方和
        sumof_x2 = sum([pow(i, 2) for i in dx])
        sumof_y2 = sum([pow(j, 2) for j in dy])
        num = sumof_xy - (float(sum1) * float(sum2) / nn)
        # 计算皮尔逊相关系数
        den = math.sqrt((sumof_x2 - float(sum1 ** 2) / nn) * (sumof_y2 - float(sum2 ** 2) / nn))
        self.steps.append(["", "两个变量的相关系数为: %s" % new_latex(num / den)])
        return self


# 求平均数
"""
1.输入: table = {'x': [87,88,91,91,93]}
"""


class GLTJAverage001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        data = table['x']
        sums = 0
        for item in data:
            sums += sympify(item)
        aver = sums / len(data)
        self.steps.append(["", "平均数为 %s" % new_latex(aver)])
        return self


# 求方差
"""
1.输入: table = {'x': [87,88,91,91,93]}
"""


class GLTJVariance001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        data = table['x']
        sums = 0
        for item in data:
            sums += sympify(item)
        aver = sums / len(data)
        self.steps.append(["", "平均数为 %s" % new_latex(aver)])
        variance = 0
        for item in data:
            variance += (sympify(item) - aver) ** 2
        variance = variance / len(data)
        self.steps.append(["", "方差为 %s" % new_latex(variance)])
        return self


#
"""
1.输入: table = {'x': [87,88,91,91,93]}
"""


class GLTJStandardDeviation001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        data = table['x']
        sums = 0
        for item in data:
            sums += sympify(item)
        aver = sums / len(data)
        self.steps.append(["", "平均数为 %s" % new_latex(aver)])
        variance = 0
        for item in data:
            variance += (sympify(item) - aver) ** 2
        variance = variance / len(data)
        self.steps.append(["", "方差为 %s" % new_latex(variance)])
        standard_deviation = sqrt(variance)
        self.steps.append(["", "标准差为 %s" % new_latex(standard_deviation)])
        return self


# 求2X2卡方值
"""
1.输入:
    a=80
    b=30
    c=40
    d=50
"""


class GLTJChiSquare001(BaseFunction):
    def solver(self, *args):
        aa = args[0]
        bb = args[1]
        c = args[2]
        d = args[3]
        nn = aa + bb + c + d
        k_2 = nn * ((aa * d - bb * c) ** 2) / ((aa + bb) * (aa + c) * (c + d) * (bb + d))
        self.steps.append(["", "计算卡方值,得"])
        self.steps.append(["", "K^{2} = %s" % new_latex(k_2)])
        return self


# 频率分布直方图
"""
1.table = {(10,35):0.004,(35,60):0.012,(60,85):0.016,(85,110):0.008}
"""


class GLTJPLFBZFT001(BaseFunction):
    def solver(self, *args):
        import matplotlib.pyplot as plt
        table = args[0]
        list_left = []
        list_height = []
        for item in table.items():
            list_left.append(sum(item[0]) / 2)
            list_height.append(item[1])
        plt.title('frequency distribution histogram')
        plt.show()
        return self


# 根据频数求总数
"""
1.table = {(10,35):0.004,(35,60):0.012,(60,85):0.016,(85,110):0.008}
target = {(10, 35): 80}
"""


class GLTJPLFBZFT002(BaseFunction):
    def solver(self, *args):
        table = args[0]
        target = args[1]
        target_key = target.keys()[0]
        zu_ju = target_key[1] - target_key[0]
        p = table[target_key] * zu_ju
        self.steps.append(["", "%s内的频率为%s" % (new_latex(target_key), new_latex(p))])
        sum_num = target[target_key] / p
        self.steps.append(["", "总数量为 %s" % new_latex(sum_num)])
        return self


# 根据频数求总数
"""
1.table = {(70,80):0.002,(80,90):0.005,(90,100):'x',(100,110):0.02,(110,120):0.025,(120,130):0.02,(130,140):'x',(140,150):0.008}
"""


class GLTJPLFBZFT003(BaseFunction):
    def solver(self, *args):
        table = args[0]
        sum_fre = 0
        for data_fre in table.items():
            class_interval = int(data_fre[0][1]) - int(data_fre[0][0])
            class_p = sympify(data_fre[1])
            sum_fre += class_interval * class_p
        self.steps.append(["", "∵ 各长方形的面积之和为1"])
        self.steps.append(["", "∴ %s" % BaseEq([sum_fre, 1]).printing()])
        symbols = list(sum_fre.free_symbols)
        assert len(symbols) == 1
        symbol = symbols[0]
        answer = solve(sum_fre - 1, symbol)[0]
        self.steps.append(["", "解得: %s" % BaseEq([symbol, answer]).printing()])
        return self


# 以直方图的中点作为平均值求整体的平均值
"""
1.table = {(40, 50): 0.01, (50, 60): 0.02, (60, 70): 0.04, (70, 80): 0.02, (80, 90): 0.01}
"""


class GLTJPLFBZFT004(BaseFunction):
    def solver(self, *args):
        table = args[0]
        aver = 0
        for data in table.items():
            zu_ju = data[0][1] - data[0][0]
            p = zu_ju * data[1]
            mid_value = (data[0][0] + data[0][1]) / 2
            aver += p * mid_value
        self.steps.append(["", "平均数为 %s" % new_latex(aver)])
        return self


# 以直方图的中点作为平均值求整体的方差
"""
1.table = {(40, 50): 0.01, (50, 60): 0.02, (60, 70): 0.04, (70, 80): 0.02, (80, 90): 0.01}
"""


class GLTJPLFBZFT005(BaseFunction):
    def solver(self, *args):
        table = args[0]
        aver = 0
        for data in table.items():
            zu_ju = data[0][1] - data[0][0]
            p = zu_ju * data[1]
            mid_value = (data[0][0] + data[0][1]) / 2
            aver += p * mid_value
        variance = 0
        for data in table.items():
            zu_ju = data[0][1] - data[0][0]
            p = zu_ju * data[1]
            mid_value = (data[0][0] + data[0][1]) / 2
            variance += p * (mid_value - aver) ** 2
        self.steps.append(["", "方差为 %s" % new_latex(variance)])
        return self


# 计算频率分布直方图某一事件的概率
class GLTJPLFBZFT006(BaseFunction):
    def solver(self, *args):
        tables = args[0]
        text = args[1]
        tables_keys = tables.keys()
        target_table_data = None
        for tables_key in tables_keys:
            if text.find(tables_key) >= 0:
                target_table_data = tables[tables_key]
        m = re.findall(r'(\w*[0-9]+)\w*', text)
        m = [sympify(item) for item in m]
        assert len(m) == 1
        m = m[0]
        ping_lv_sums = 0
        if text.find("低于") >= 0 or text.find("<") >= 0 or text.find("≤") >= 0 or text.find("小于") >= 0:
            target_table_data_keys = target_table_data.keys()
            for target_table_data_key in target_table_data_keys:
                left, right = target_table_data_key
                if right <= m:
                    ping_lv = (right - left) * target_table_data[target_table_data_key]
                    ping_lv_sums += ping_lv
        elif text.find("高于") >= 0 or text.find("≥") >= 0 or text.find(">") >= 0 or text.find("大于") >= 0:
            target_table_data_keys = target_table_data.keys()
            for target_table_data_key in target_table_data_keys:
                left, right = target_table_data_key
                if left >= m:
                    ping_lv = (right - left) * target_table_data[target_table_data_key]
                    ping_lv_sums += ping_lv
        self.steps.append(["", text + "的频率为%s" % new_latex(ping_lv_sums)])
        return self


# 计算频率分布直方图的2×2列联表参数
class GLTJPLFBZFT007(BaseFunction):
    def solver(self, *args):
        tables = args[0]
        text = args[1]
        nums = args[2]
        tables_keys = tables.keys()
        target_table_data = None
        for tables_key in tables_keys:
            if text.find(tables_key) >= 0:
                target_table_data = tables[tables_key]
        m = re.findall(r'(\w*[0-9]+)\w*', text)
        m = [sympify(item) for item in m]
        assert len(m) == 1
        m = m[0]
        ping_lv_sums = 0
        if text.find("低于") >= 0 or text.find("<") >= 0 or text.find("≤") >= 0 or text.find("小于") >= 0:
            target_table_data_keys = target_table_data.keys()
            for target_table_data_key in target_table_data_keys:
                left, right = target_table_data_key
                if right <= m:
                    ping_lv = (right - left) * target_table_data[target_table_data_key]
                    ping_lv_sums += ping_lv
        elif text.find("高于") >= 0 or text.find("≥") >= 0 or text.find(">") >= 0 or text.find("大于") >= 0:
            target_table_data_keys = target_table_data.keys()
            for target_table_data_key in target_table_data_keys:
                left, right = target_table_data_key
                if left >= m:
                    ping_lv = (right - left) * target_table_data[target_table_data_key]
                    ping_lv_sums += ping_lv
        target = ping_lv_sums * nums
        self.steps.append(["", text + "的频率为%s" % new_latex(ping_lv_sums)])
        self.output.append(BaseNumber(target))
        self.steps.append(["", text + "的数量为%s" % new_latex(target)])
        return self


# 茎叶图数据转化
"""
1.table = {1: [9,8,8],2: [6,1,0],3: [5,3,2,0],4: [7,0,1]}
"""


class GLTJJYT001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        list_data = []
        for data in table.items():
            for small_num in data[1]:
                list_data.append(10 * data[0] + small_num)
        self.steps.append(["", "茎叶图的数据转化为 %s" % new_latex(list_data)])
        self.output.append({'x': list_data})
        return self


# 求中位数
"""
1.table = {'x': [19, 18, 18, 26, 21, 20, 35, 33, 32, 30, 47, 40, 41]}
"""


class GLTJMedian001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        list_data = table['x']
        list_data.sort()
        self.steps.append(["", "按从小到大的顺序排序,得"])
        self.steps.append(["", "%s" % ",".join(["%s" % new_latex(data) for data in list_data])])
        if len(list_data) % 2 == 1:
            mid_data = list_data[int((len(list_data) - 1) / 2)]
        else:
            mid_data = (list_data[int((len(list_data)) / 2 - 1)] + list_data[int((len(list_data)) / 2)]) / 2
        self.steps.append(["", "∴ 中位数为 %s" % new_latex(mid_data)])
        return self


# 求众数
"""
1.table = {'x': [19, 18, 18, 26, 21, 20, 35, 33, 32, 30, 47, 40, 41]}
"""


class GLTJMode001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        list_data = table['x']
        list_data.sort()
        self.steps.append(["", "按从小到大的顺序排序,得"])
        self.steps.append(["", "%s" % ",".join(["%s" % new_latex(data) for data in list_data])])
        max_num = 0
        max_num_data = 0
        for data in list_data:
            if list_data.count(data) > max_num:
                max_num = list_data.count(data)
                max_num_data = data
        self.steps.append(["", "∴ 众数为 %s" % new_latex(max_num_data)])
        return self


# 求最大值
"""
1.table = {'x': [19, 18, 18, 26, 21, 20, 35, 33, 32, 30, 47, 40, 41]}
"""


class GLTJMax001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        list_data = table['x']
        list_data.sort()
        self.steps.append(["", "按从小到大的顺序排序,得"])
        self.steps.append(["", "%s" % ",".join(["%s" % new_latex(data) for data in list_data])])
        self.steps.append(["", "∴ 最大值为 %s" % new_latex(max(list_data))])
        return self


# 求最小值
"""
1.table = {'x': [19, 18, 18, 26, 21, 20, 35, 33, 32, 30, 47, 40, 41]}
"""


class GLTJMin001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        list_data = table['x']
        list_data.sort()
        self.steps.append(["", "按从小到大的顺序排序,得"])
        self.steps.append(["", "%s" % ",".join(["%s" % new_latex(data) for data in list_data])])
        self.steps.append(["", "∴ 最小值为 %s" % new_latex(min(list_data))])
        return self


# 求极差
"""
1.table = {'x': [19, 18, 18, 26, 21, 20, 35, 33, 32, 30, 47, 40, 41]}
"""


class GLTJRange001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        list_data = table['x']
        list_data.sort()
        self.steps.append(["", "按从小到大的顺序排序,得"])
        self.steps.append(["", "%s" % ",".join(["%s" % new_latex(data) for data in list_data])])
        self.steps.append(["", "∴ 极差为 %s" % new_latex(max(list_data) - min(list_data))])
        return self


# 分层抽样
"""
1.table = {'高一学生': 400, '高二学生': 400, '高三学生': 400}
  target = {'高一学生': 80}
"""


class GLTJStratifiedSampling001(BaseFunction):
    def solver(self, *args):
        table = args[0]
        target = args[1]
        sum_total = 0
        for data_total in table.items():
            sum_total += sympify(data_total[1])
        self.steps.append(["", "求得总体容量为 %s" % new_latex(sum_total)])
        for data_select in target.items():
            xx = int(round(data_select[1] * sum_total / table[data_select[0]]))
        self.steps.append(["", "故按比例，求得抽取总量为 %s" % new_latex(xx)])
        return self


if __name__ == '__main__':
    pass
